<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>文档</title>
  <link href="../css/semantic/semantic.min.css" rel="stylesheet">
  <link href="../css/markdown.css" rel="stylesheet">
    <link href="../css/wtxynavigation.css" rel="stylesheet">
    <script src="../js/jquery.min.js"></script>
    <script type="text/javascript" src="../js/include.js"></script>
  <style>
    body{padding-top:0;background:#f7f7f7}
    body>.ui.container{width:100%;padding:0}
    #project-title{background:#6e6e6e;width:100%;line-height:3.572rem;color:#fff;font-size:1.2rem}
    #project-title .title-wrap{font-weight:700;padding:0 12px;width:100%;max-width:1366px!important;min-width:900px;margin:0 auto}
    #project-title .left,#project-title right{display:inline-block}
    #project-title .right{float:right}
    #project-title .right .wiki-actions .menu{left:auto;right:0;margin-top:.4em!important}
    #wiki-preview-container{width:100%;max-width:1366px!important;min-width:900px;padding:0;border:1px solid #e3e9ed;border-top:0}
    #wiki-preview>.ui.segment{margin-top:0;padding:1rem;padding-left:0;border:0}
    .hover-places{display:inline-block}
    #page-detail{width:60%;margin:0 auto}
    #page-detail .title{font-weight:700;font-size:24px;padding:12px 0;border-bottom:1px solid #ccc}
    #page-detail .content{margin-top:15px}
    .content p{word-wrap:break-word}
    #wiki-parent,#wiki-title,#wikis{display:none}
    .ui.grid{padding:0!important}
    #ex-all{cursor:pointer;color:#537c8d}
  </style>
</head>
<body>
  <div class="ui container">
    <div id="project-title">
      <div class="title-wrap">
        <div class="left">
          <i class="icon eye"></i>
          文档预览:
          mianmSDK
        </div>
        <div class="right">
          Export by Gitee
        </div>
      </div>
    </div>

    <div class="ui container" id="wiki-preview-container">
      <div id="wiki-preview">
        <div class="ui segment">
          <div id="page-detail" class="markdown-body">
            <div class='title'>27.runtime消息转发流程</div><div class='content'><h1>
<a id="27runtime消息转发流程" class="anchor" href="#27runtime%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%B5%81%E7%A8%8B"></a>27.runtime消息转发流程</h1>
<h1>
<a id="消息传递" class="anchor" href="#%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92"></a>消息传递</h1>
<p><img src="images/runtime2021051503.png" alt="runtime2021051503"></p>
<h1>
<a id="消息转发" class="anchor" href="#%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91"></a>消息转发</h1>
<p><img src="images/runtimeMsgSend01.png" alt="runtimeMsgSend01"></p>
<p><strong>关键词</strong>: <code>runtime</code></p>
<h1>
<a id="1-resolveinstancemethod" class="anchor" href="#1-resolveinstancemethod"></a>1. +resolveInstanceMethod</h1>
<pre><code>
+ (BOOL)resolveInstanceMethod:(SEL)sel

</code></pre>
<ul>
<li>返回YES: 消息已处理, 结束消息转发流程</li>
<li>返回NO: 系统给我们第二次机会⏬ <code>-forwardingTargetForSelector</code>
</li>
</ul>
<h1>
<a id="2--forwardingtargetforselector" class="anchor" href="#2--forwardingtargetforselector"></a>2. -forwardingTargetForSelector</h1>
<pre><code>
- (id)forwardingTargetForSelector:(SEL)aSelector

</code></pre>
<ul>
<li>
<strong>id</strong>: 返回一个对象, 这个对象处理本次的方法选择器SEL</li>
<li>返回一个对象: 消息已处理, 转发目标处理,</li>
<li>返回<code>nil</code>: 系统给我们第三次机会 <code>-methodSignatureForSelector</code>
</li>
</ul>
<h1>
<a id="3--methodsignatureforselector" class="anchor" href="#3--methodsignatureforselector"></a>3. -methodSignatureForSelector</h1>
<pre><code>
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

</code></pre>
<ul>
<li>
<code>NSMethodSignature</code>类型: 是对方法选择器的返回值类型, 以及参数个数,以及参数类型的封装, 就是方法签名</li>
<li>返回一个方法签名: 系统就调用<code>forwardInvocation</code>, 如果<code>forwardInvocation</code>能够处理的话, 消息转发流程就结束</li>
<li>返回<code>nil</code>: 消息无法处理</li>
</ul>
<h2>
<a id="31参数解释" class="anchor" href="#31%E5%8F%82%E6%95%B0%E8%A7%A3%E9%87%8A"></a>3.1参数解释</h2>
<pre><code>
[NSMethodSignature  signatureWithObjCTypes:"v@:"];

</code></pre>
<ul>
<li>
<strong>v</strong> 代表返回值<code>void</code>类型</li>
<li>
<strong>@</strong> 代表第一个参数类型是<code>id</code>, 即<code>self</code>
</li>
<li>
<strong>:</strong> 代表第二个参数是<strong>SEL</strong>类型 即<code>@selector(test)</code>
</li>
</ul>
<h1>
<a id="4--forwardinvocation" class="anchor" href="#4--forwardinvocation"></a>4. -forwardInvocation</h1>
<pre><code>
- (void)forwardInvocation:(NSInvocation *)anInvocation

</code></pre>
<h1>
<a id="code" class="anchor" href="#code"></a>code</h1>
<p><img src="images/runtimeMsgSend02.png" alt="runtimeMsgSend02"></p>
<p><strong>.h</strong></p>
<pre><code>
@interface WTUserCenter : NSObject

- (void)test;
+ (void)test;
@end


</code></pre>
<p><strong>.m</strong></p>
<pre><code>
@interface WTUserCenter ()


@end

@implementation WTUserCenter


///**
// 类方法调用
// */
//+ (BOOL)resolveClassMethod:(SEL)sel
//{
//    
//    return YES;
//}
//
/**
 实例方法调用
 sel : 方法选择器

 返回YES: 消息已处理, 结束消息转发流程
 返回NO: 系统给我们第二次机会⏬ forwardingTargetForSelector
 */
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    

    if (sel == @selector(test)) {
        
        NSLog(@"🙂%s", __func__);
        return YES;
    }else{
        
        return [super resolveInstanceMethod:sel];
    }
    
    
}

/**
 第二次机会正是在下

 id: 返回一个对象, 这个对象处理本次的方法选择器SEL

 返回一个对象: 消息已处理, 转发目标处理,
 返回nil: 系统给我们第三次机会 ⏬ methodSignatureForSelector
 */
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    NSLog(@"🙂%s", __func__);
    return nil;//[WTUserTest new];
}

/**
 第三次机会正是在下

 NSMethodSignature类型: 是对方法选择器的返回值类型, 以及参数个数,以及参数类型的封装, 就是方法签名

 返回一个方法签名: 系统就调用forwardInvocation, 如果forwardInvocation能够处理的话, 消息转发流程就结束
 返回nil: 消息无法处理
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    
    if (aSelector == @selector(test)) {
        
        // v 代表返回值void类型
        // @ 代表第一个参数类型是id, 即self
        // : 代表第二个参数是SEL类型 即@selector(test)
        NSLog(@"🙂%s", __func__);
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }else{
        
        return [super methodSignatureForSelector:aSelector];
    }
    
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"🙂%s", __func__);
}

@end

</code></pre></div>
          </div>
        </div>
      </div>
      </div>
  </div>
</body>
</html>